module sw.wiki.article;

version(Wiki):
import std.string, std.stdio, std.file, std.uri, nazo.date, std.conv, core.thread;
import sw.wiki.preflist, sw.wiki.backuplist, sw.wiki.recentlist, sw.wiki.pagelist, sw.wiki.dat;

///ページ
struct Article{
  public{
    ///dat
    Dat dat;
    private Dat _timedDat;
    ///timed dat(dat/title.nowtime.dat)
    Dat timedDat(){
      if(!_timedDat)_timedDat=new Dat(title,std.string.toString(.toUtime(getUTCtime())));
      return _timedDat;
    }
    ///エスケープされてない名前
    string title;
    ///最終更新の前の更新の時刻
    string lastBackup;
    private BackupList _backupList;
    ///バックアップの一覧
    BackupList backupList(){
      if(!_backupList)_backupList=new BackupList(dat.fileName);
      return _backupList;
    }
    private PageList _pageList;
    ///ページの一覧
    PageList pageList(){
      if(!_pageList)_pageList=new PageList;
      return _pageList;
    }
    ///履歴の一覧
    private RecentList _recent;
    RecentList recent(){
      if(!_recent)_recent=new RecentList;
      return _recent;
    }
    ///設定の一覧
    PrefList prefs;
    ///書き込み可能かどうか(freezeと同じ)
    bool writable=true;
    ///最終更新時刻
    string lastModified;
    ///コメントの数
    uint commentLength;
    ///状態の最新更新日
    d_time stateLastModified(){
      d_time page=.getUTCtimeFromUtime(.toUint(lastModified));
      d_time prefs=prefs.lastModified;
      if(page<prefs)return prefs;
      return page;
    }
    ///コンストラクタ
    static Article opCall(string name){
      Article rv;
      rv.title=name;
      rv.dat=new Dat(name);
      rv.prefs=new PrefList(rv.dat.fileName);
      rv.writable=cast(bool)(rv.prefs.getValue("writable")!="0");
      rv.lastModified=rv.prefs.getValue("lastModified");
      if(rv.lastModified=="")rv.lastModified="0";
      rv.lastBackup=rv.prefs.getValue("lastBackup");
      string tmp=rv.prefs.getValue("commentLength");
      if(tmp!="")rv.commentLength=.toUint(tmp);
      return rv;
    }
    void addCommentLength(){
      this.commentLength++;
      this.prefs.setValue("commentLength",std.string.toString(this.commentLength));
      this.prefs.flash();
    }
    void removeCommentLength(){
      this.commentLength--;
      this.prefs.setValue("commentLength",std.string.toString(this.commentLength));
      this.prefs.flash();
    }
    ///dat読み込み
    string read(){
      return dat.read();
    }
    ///バックアップのdat読み込み
    string backupRead(string time){
      Dat backupDat=new Dat(this.title,time);
      return backupDat.read();
    }
    ///バックアップの削除
    void backupDelete(string time){
      Dat backupDat=new Dat(this.title,time);
      backupDat.remove();
      this.backupList.remove(time);
      //既にdatが無くてバックアップが現在のだけなら
      if(!dat.isExist&&this.backupList.length==1){
        this.backupList.removeList();
        prefs.removeAll();
        prefs.flash();
      }
    }
    ///凍結
    void freeze(){
      this.writable=false;
      this.prefs.setValue("writable",(this.writable?"1":"0"));
      this.prefs.flash();
    }
    ///凍結解除
    void unfreeze(){
      this.writable=true;
      this.prefs.setValue("writable",(this.writable?"1":"0"));
      this.prefs.flash();
    }
    ///書き込み
    void write(string data){
      //コンフリクト全く考えてない
      if(data==""){///Bugs: 履歴まで消してる&既にdatが無いときの処理がおかしい。
        if(dat.isExist()){
          dat.remove();
          this.pageList.remove(this.title);
          this.recent.remove(lastModified~" "~this.title);
          this.prefs.removeAll();
          this.prefs.flash();
        }else{
          if(this.backupList.length==0){
            this.backupList.removeList();
            prefs.removeAll();
            prefs.flash();
            return;
          }
        }
      }else{
        if(!dat.isExist()){
          this.pageList.append(this.title);
        }
        dat.write(data);
        timedDat.write(data);
        this.recent.remove(this.lastModified~" "~this.title);
        this.recent.append(timedDat.time~" "~this.title);
      }
      this.prefs.removeAll();
      this.prefs.setValue("lastModified",timedDat.time);
      this.prefs.setValue("lastBackup",this.lastModified);
      this.prefs.setValue("writable",(this.writable?"1":"0"));
      this.prefs.flash();
      this.backupList.append(timedDat.time);
    }
  }
}
